package red.uec.service.impl;

import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import red.uec.entity.User;
import red.uec.exception.BusinessException;
import red.uec.jwt.JwtHelper;
import red.uec.jwt.JwtPayload;
import red.uec.mapper.UserMapper;
import red.uec.model.*;
import red.uec.service.UserService;
import red.uec.sms.SmsClient;
import red.uec.util.IdGenerator;
import red.uec.util.PasswordUtils;
import red.uec.util.RandomCodeUtil;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 谭剑晖
 * @since 2018-08-22
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private JwtHelper jwtHelper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SmsClient smsClient;

    public RegisterMessageCodeResponse getMessageCode(RegisterMessageCodeRequest registerMessageCodeRequest){
        // 检查手机号是否已注册
        int count = this.selectCount(Condition.create().setSqlSelect("count 1").eq("mobile", registerMessageCodeRequest.getMobile()));
        if(count > 0){
            throw new BusinessException("-1", "手机号已经被注册");
        }

        /*// 检查电子邮箱是否已注册
        count = this.selectCount(Condition.create().setSqlSelect("count 1").eq("email", registerMessageCodeRequest.getEmail()));
        if(count > 0){
            throw new BusinessException("-1", "电子邮箱已经被注册");
        }*/

        String messageCode = RandomCodeUtil.getNumberCode(6);
        String messageCodeToken = UUID.randomUUID().toString().replace("-", "");
        String key = "register:message_code:"+registerMessageCodeRequest.getMobile();
        String value = messageCodeToken + ":" + messageCode;

        if(redisTemplate.getExpire(key) > 0){
            throw new BusinessException("-1", "短信验证码已发送到您的手机，请注意查收！");
        }
        redisTemplate.opsForValue().set(key, value,120, TimeUnit.SECONDS);
        log.info("messageCodeToken: {} \n messageCode: {}", messageCodeToken, messageCode);

        // 发送短信
        smsClient.sendCode(registerMessageCodeRequest.getMobile(), messageCode);

        RegisterMessageCodeResponse registerMessageCodeResponse = new RegisterMessageCodeResponse();
        registerMessageCodeResponse.setMessageCodeToken(messageCodeToken);

        return registerMessageCodeResponse.success("短信验证码已发送到您的手机，请注意查收！");
    }

    @Transactional(rollbackFor = {Exception.class})
    public RegisterResponse register(RegisterRequest registerRequest){

        // 检查手机号是否已注册
        int count = this.selectCount(Condition.create().setSqlSelect("count 1").eq("mobile", registerRequest.getMobile()));
        if(count > 0){
            throw new BusinessException("-1", "手机号已经被注册");
        }

        /*// 检查电子邮箱是否已注册
        count = this.selectCount(Condition.create().setSqlSelect("count 1").eq("email", registerRequest.getEmail()));
        if(count > 0){
            throw new BusinessException("-1", "电子邮箱已经被注册");
        }*/

        // 检查短信验证码
        String key = "register:message_code:"+registerRequest.getMobile();
        String value = (String)redisTemplate.opsForValue().get(key);
        if(!StringUtils.equals(value, registerRequest.getMessageCodeToken() + ":" + registerRequest.getMessageCode())){
            throw new BusinessException("-1", "请输入正确的短信验证码");
        }

        User user = new User();
        user.setId(IdGenerator.newId());
        user.setMobile(registerRequest.getMobile());
        user.setPassword(PasswordUtils.digest(user.getId() + ":" + registerRequest.getPassword()));
        /*user.setEmail(registerRequest.getEmail());*/
        user.setStatus("1");
        user.setCreateTime(new Date());
        user.setCreator(user.getId());
        user.setModifyTime(user.getCreateTime());
        user.setModifier(user.getId());

        this.insert(user);

        return new RegisterResponse().success();
    }

    public LoginResponse login(LoginRequest loginRequest){

        User user = this.selectOne(
                Condition.create()
                        .setSqlSelect("*")
                        .eq("mobile", loginRequest.getMobile()));

        if(null == user){
            return new LoginResponse().fail("用户名或密码错误");
        }

        String password = PasswordUtils.digest(user.getId() + ":" + loginRequest.getPassword());
        if(!StringUtils.equals(password, user.getPassword())){
            return new LoginResponse().fail("用户名或密码错误");
        }

        JwtPayload jwtPayload = new JwtPayload(user.getId(), user.getMobile(), user.getMobile());
        String jwt = jwtHelper.createToken(jwtPayload);

        LoginResponse loginResponse = new LoginResponse();
        loginResponse.setJwt(jwt);
        return loginResponse.success();
    }

    public PasswordModificationResponse modifyPassword(PasswordModificationRequest passwordModificationRequest){
        User user = this.selectById(passwordModificationRequest.getUserId());

        if(null == user){
            return new PasswordModificationResponse().fail("用户不存在");
        }

        String password = PasswordUtils.digest(user.getId() + ":" + passwordModificationRequest.getOriginPassword());
        if(!StringUtils.equals(password, user.getPassword())){
            return new PasswordModificationResponse().fail("原密码错误");
        }

        user.setPassword(PasswordUtils.digest(user.getId() + ":" + passwordModificationRequest.getNewPassword()));
        this.updateById(user);
        return new PasswordModificationResponse().success();
    }

    public PasswordResetMessageCodeResponse getPasswordResetMessageCode(PasswordResetMessageCodeRequest passwordResetMessageCodeRequest){
        // 检查手机号是否已注册
        int count = this.selectCount(Condition.create().setSqlSelect("count 1")
                .eq("mobile", passwordResetMessageCodeRequest.getMobile()));
        if(count == 0){
            throw new BusinessException("-1", "手机号错误");
        }

        String messageCode = RandomCodeUtil.getNumberCode(6);
        String messageCodeToken = UUID.randomUUID().toString().replace("-", "");
        String key = "password:reset:message_code:"+passwordResetMessageCodeRequest.getMobile();
        String value = messageCodeToken + ":" + messageCode;

        if(redisTemplate.getExpire(key) > 0){
            throw new BusinessException("-1", "短信验证码已发送到您的手机，请注意查收！");
        }
        redisTemplate.opsForValue().set(key, value,120, TimeUnit.SECONDS);
        log.info("messageCodeToken: {} \n messageCode: {}", messageCodeToken, messageCode);

        // 发送短信
        smsClient.sendCode(passwordResetMessageCodeRequest.getMobile(), messageCode);

        PasswordResetMessageCodeResponse passwordResetMessageCodeResponse = new PasswordResetMessageCodeResponse();
        passwordResetMessageCodeResponse.setMessageCodeToken(messageCodeToken);

        return passwordResetMessageCodeResponse.success("短信验证码已发送到您的手机，请注意查收！");
    }

    public PasswordResetResponse resetPassword(PasswordResetRequest passwordResetRequest){
        // 检查手机号是否已注册
        User user = this.selectOne(Condition.create().setSqlSelect("id")
                .eq("mobile", passwordResetRequest.getMobile()));
        if(null == user){
            throw new BusinessException("-1", "手机号错误");
        }

        // 检查短信验证码
        String key = "password:reset:message_code:"+passwordResetRequest.getMobile();
        String value = (String)redisTemplate.opsForValue().get(key);
        if(!StringUtils.equals(value, passwordResetRequest.getMessageCodeToken() + ":" + passwordResetRequest.getMessageCode())){
            throw new BusinessException("-1", "请输入正确的短信验证码");
        }

        user.setPassword(PasswordUtils.digest(user.getId() + ":" + passwordResetRequest.getPassword()));
        this.updateById(user);
        return new PasswordResetResponse().success();
    }
}
